// Copyright 2011, Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package jku.mobcomp;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import jku.mobcomp.helper.Utility;

import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;
import com.google.appengine.api.datastore.Entity;

/**
 * This servlet responds to the request corresponding to boulder. The class
 * creates and manages the BoulderEntity
 * 
 * 
 */
@SuppressWarnings("serial")
public class BoulderServlet extends BaseServlet {

  private static final Logger logger = Logger.getLogger(BoulderServlet.class.getCanonicalName());

  /**
   * Searches for the entity based on the search criteria and returns result in
   * JSON format
   */
  protected void doGet(HttpServletRequest req, HttpServletResponse resp)
	      throws ServletException, IOException {

	    super.doGet(req, resp);
	    logger.log(Level.INFO, "Obtaining Boulder listing");
	    String searchBy = req.getParameter("boulder-searchby");
	    String searchFor = req.getParameter("q");
	    String keyId = req.getParameter("keyId");
	    String resize = req.getParameter("resize");
	    String user = req.getParameter("user");
	    Iterable<Entity> entities =null;
	    PrintWriter out = resp.getWriter();
	    if (keyId != null && !keyId.equals("")) {
	    	Long keyIdLng = Utility.convertStringToLong(keyId);
	    	Entity entity = Boulder.getSingleBoulderById(keyIdLng);
	        entities = Utility.putEntityInIterable(entity);
	    } else  if (searchFor == null || searchFor.equals("")) {
	    	entities = Boulder.getAllBoulders();
	    } else if (searchBy == null || searchBy.equals("name")) {
	    	entities = Boulder.getBouldersByName(searchFor);
	    } else if (searchBy == null || searchBy.equals("like")) {
		      entities = Boulder.getBouldersByLike(searchFor);
	    } else if (searchBy == null || searchBy.equals("grade")) {
		      entities = Boulder.getBouldersByGrade(searchFor);
	    } else if (searchBy != null && searchBy.equals("country")) {
	      entities = Boulder.getBouldersForCountry( searchFor);
	    }

	    writeBoulders(req, out, entities, user);

	    // special action for resizing all selected boulder (make the small/large images)
	    if (resize!=null && resize.equals("true")){
		       Boulder.resizeImages( entities);
		}
	    
	  }

  /**
   * Creates entity and persists the same
   */
  protected void doPut(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
	String keyId = req.getParameter("keyId");
    String name = req.getParameter("name");
    logger.log(Level.INFO, "Creating Boulder: "+ name);
    String description = req.getParameter("description");
    String lat = req.getParameter("lat");
    String lon = req.getParameter("lon");
    String grade = req.getParameter("grade");
    String line = req.getParameter("line");
    String countryId = req.getParameter("country");
    String user = req.getParameter("user");
    String imageCleanBase64 = req.getParameter("imageBase64");
    String imageLineBase64 = req.getParameter("imageLineBase64");
    String imageType= req.getParameter("imageType");
    String imageIsLine= req.getParameter("imageIsLine");
    
    // check if there are binary images upload by employing "multipart/form-data"
    // user try/catch for reading blobs, because this command is only allowed after a
    // redirection after uploading binaryImage
    BlobKey blobKey = null;
	try {
		BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
//		Map<String, BlobKey> blobs;
//		blobs = blobstoreService.getUploadedBlobs(req);
//	    blobKey = blobs.get("myFile");
		Map<String, List<BlobKey>> blobKeyMap;
		blobKeyMap = blobstoreService.getUploads(req);
		if (blobKeyMap!=null) {
			Collection<List<BlobKey>> blobKeyColl = blobKeyMap.values();
			if (blobKeyColl!=null) {
				  Iterator<List<BlobKey>> it = blobKeyColl.iterator();
				  if (it.hasNext()){
					  List<BlobKey> blobKeyList = it.next();
					  if (blobKeyList!=null) {
						  Iterator<BlobKey> it2 = blobKeyList.iterator();
						  if (it2.hasNext()){
							  blobKey = it2.next();
						  }
					  }
				  }
			}
		}
	} catch (IllegalStateException e) {
	}
	
    boolean blobKeyIsLine = false;
    if (imageIsLine != null && imageIsLine.equalsIgnoreCase("true") ) {
    	blobKeyIsLine = true;
    }
	
    Entity boulder = Boulder.createOrUpdateBoulder( keyId, name, description, lat, lon, 
    		grade, line, countryId, user, imageCleanBase64, imageLineBase64, imageType, 
    		blobKey, blobKeyIsLine);

    PrintWriter out = resp.getWriter();
    Iterable<Entity> entities = Utility.putEntityInIterable(boulder);  
    writeBoulders(req, out, entities, user);
	
  }

  /**
   * Delete the entity from the datastore. Throws an exception if there are any
   * orders associated with the boulder and ignores the delete action for it.
   */
  protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
		String keyId = req.getParameter("keyId");
	    logger.log(Level.INFO, "Deleting Boulder: " + keyId);
    PrintWriter out = resp.getWriter();
    try{      
      out.println(Boulder.deleteBoulder(keyId));
    } catch(Exception e) {
      out.println(Utility.getErrorMessage(e));
    }      
    
  }

  /**
   * Redirects to delete or insert entity based on the action in the HTTP
   * request.
   */
  protected void doPost(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    String action = req.getParameter("action");
    if (action.equalsIgnoreCase("delete")) {
      doDelete(req, resp);
      return;
    } else if (action.equalsIgnoreCase("put")) {
      doPut(req, resp);
      return;
    }
  }
  

  /**
   * Write a Collection of Boulders to Response
   */
  private void writeBoulders(HttpServletRequest req, PrintWriter out, Iterable<Entity> entities, 
		  String userForCheckRatingDone) {

	    String posLat = req.getParameter("posLat");
	    String posLon = req.getParameter("posLon");
	    String maxDistance = req.getParameter("maxDistance");
	    String sortBy = req.getParameter("boulder-sortby");
	    String maxRecords = req.getParameter("maxRecords");
	    if (entities != null) {
	    	// calculate and append additional Data
	    	 Iterable<Entity> resultEntities = Boulder.appendBoulderResultProperties(entities, 
	    			 posLat, posLon, maxDistance, userForCheckRatingDone);
	    	 // Sort the result
	    	 Iterable<Entity> resultEntitiesSorted = Utility.sortEntities(resultEntities, 
	    			 sortBy, maxRecords);
	    	 // Write result als JSON
	    	 String msgJSON = Utility.writeJSON(resultEntitiesSorted);
	    	 out.println(msgJSON);
	    	 logger.log(Level.INFO, "Msg-JSON Boulder: "+ msgJSON);
	    }
  }
  
}